Файлы
======

.. index::
  file
  File
  файл

Мы видели в предыдущей главе, что стандартные потоки ввода/вывода можно перенаправлять
в файл и из файла, а так же из других программ и в другие программы, используюя опреаторы : >, <, | в командной строке терминала.
Не смотря на то что - это очень мощные средства,эти инструменты могут быть не удобны в к каждой ситуации,
потому что в большинстве случаев программы не могут выполнить, поставленные перед ними задачи, только используя
чтение входных данных и печатая выввод на экран терминала. Например, программа работатет с записями студентов может использовать
стандартный поток вывода на монитор для создания меню. Такая программа нуждаентся в записи данных в файл, а не печатая их в стандартный вывод
В этой главе, мы займёмся чтением и записью в файл и чтение из файла, расположеных на файловой системе.

Основные концепции
-------------------

Файлы представлены структурой File определенной в модуле std.stdio. Поскольку я не предсталял эту структуру до этого
мы примемем синтаксис структуры как есть. Перед рассмотрением конкретных примеров, мы должны рассиотреть основные концепции,
связанные с файламию


**Производитель и потребитель**

Файлы созданные на одной платформе, могут оказаться недоступными для использования на прочих платформах.
Простого открытия файла и записи в него данных может быть недостаточно для
того, чтобы эти данные были доступны на стороне потребителя. Произвдитель и потребитель должны согласится
относительно формата данных в файле. Например производитель может записывать идентификатор и имя студента
в определенном порядке, тогда потребитель данных должен читать данные в том же порядке.
Дополнительно отметим, что в примерах программ ниже не записывают маркер порядка байтов (bytes oredermark or BOM)
в начало файла. Это может првести к несовместимости ваших файлов с системами требующими наличие BOM.
Примечание : BOM определяет, в каком порядке в файле расположены кодовые единицы символов UTF.


**Права доступа**

.. index::
    Права доступа
    Открытие файла
    Закрытие файла

Файловые системы предоставляют файлы программам с определенными правами доступа. Права доступа
важны как для целостности данных, так и для производительности.
Когда дело доходит до чтения, разрешение нескольким программам считывать данные из одного и того же
файла может повысить производительность, поскольку программам не придется ждать
выполнения операции чтения друг другом. С другой стороны, когда дело доходит до
записи, часто бывает полезно предотвратить одновременный доступ к файлу, даже если
только одна программа хочет выполнить запись в него. Блокируя файл, операционная система
система может препятствовать другим программам считывать частично записанные файлы,
перезаписывать данные друг друга и так далее.


**Открытие файла**

Стандартный потоки ввода/вывода уже открыты к моменту начала работы программы. Они уже готовы к использованию
С другой стороны, обычный файл,должен  быть открыт посредством указания его имени и прав доступа  необходимых для работы с ним
Так же мы увидим позднее, что для создание объекта File достаточно для открытия файла с указанием его имени.

.. code-block:: d

    File file = File("student_records", "r");


**Закрытие файла**

Любой файл открытый программой должен быть закрыт когда программа завершает использование этого файла
В большинстве случаев нет онеобходимости явного закрытия файла. Они закрываются автоматически, когда объект файл
разрушается автоматически

.. code-block:: d

    if (aCondition)
    {
      // Ппедположим объект File создается и используется в этом блоке кода
    } // В этот момент файл будет закрыт автоматически, при выхоже их этого блока кода
      // нет необходимости явного закрытия.

В некоторых случаях фаловый объект должен быть переоткрыт для использования другого файла или
использования этого же файла, но с другими правми. В этих случаях файл должен быть закрыт и открыт снова.

.. code-block:: d

    file.close();
    file.open("student_records", "r");

Writing to and reading from files
Since files are character streams, input and output functions writeln , readf , etc.
are used exactly the same way with them. The only difference is that the name of
the File variable and a dot must be typed:

**Чтение и запись в/из файла**

Так как файл есть поток символов, функции ввода/вывода : writeln, readf и прочие используются для файла обычным образом
С одной лишь разницей имя переменной типа File и точка должны быть использованы

.. code-block:: d

    writeln("hello"); // запись в стандартный поток вывода
    stdout.writeln("hello"); // то же самое, что и впредыдущей строке
    file.writeln("hello"); // запись в указанный файл



**Функция eof() для определения конца файла**


.. index::
  eof

Метод eof() определяет достигнут ли конец файла при чтении из него. Он возвращает true если конец файла достигнут
Например, следующий цикл будет активет пока не достигнут конец файла

.. code-block:: d

    while (!file.eof())
    {
        // ...
    }


**std.file модуль**

std.file модуль содержит определение функций и типов, которые будут полезны при работе с содержиммым директориев
Например, они могут быть использованы для определения существует ли данный файл или каталог на файловой системе.


.. code-block:: d

    import std.file;
    // ...
    if (exists(fileName))
    {
         // there is a file or directory under that name
    } else {
        // no file or directory under that name
    }


std.stdio.File структура
------------------------

.. index::
  std.stdio.File

Структура файла определена в модуле std.stdio . Чтобы использовать его, вы указываете
имя файла, который хотите открыть, и желаемые права доступа или режим. В нем используются
те же символы режима, которые используются в fopen
языка программирования C:

.. list-table:: Права доступа
   :widths: 25 50
   :header-rows: 1
   :align: center

   * - Режим
     - Описание
   * - r
     - доступ для чтения,файл открыт для чтения с начала файла
   * - r+
     - доступ для чтения/записи ,файл открыт/записи с начала файла
   * - w
     - доступ для записи. если файл не существует будет создан пустой файл. Если файл существует от будет очищен
   * - a
     - доступ на добавление. если файл не существует будет создан пустой файл.Если файл существует то его содержимое будет сохранено и и он будет открыт для записи в конец файла
   * - a+
     - доступ на чтение и добавление. если файл не существует будет создан пустой файл. Если существует, то содержимое будет сохранено и файл будет открыт для чтения с начала и записи в конец файла


В строку режима может быть добавлен символ "b", как в "rb". Это может иметь эффект
на платформах, поддерживающих двоичный режим, но игнорируется во всех системах POSIX.


Writing to a file
The file must have been opened in one of the write modes first:

.. index::
  Запись в файл
  Чтение из файла

**Запись в файл**

Файл должен быть открыт в одном из режимов записи перед любыми операциями записи


.. code-block:: d

    import std.stdio;

    void main()
    {
        File file = File("student_records", "w");
        file.writeln("Name : ", "Zafer");
        file.writeln("Number: ", 123);
        file.writeln("Class : ", "1A");
    }

Как вы помните из главы "Строки" (стр. 75), тип литералов типа
"student_records" - это строка, состоящая из неизменяемых символов. По этой
причине невозможно создать файловые объекты, используя изменяемый текст для указания
имени файла (например, char[] ). При необходимости вызовите свойство .idup изменяемой
строки, чтобы получить неизменяемую копию. Описанная выше программа создает или перезаписывает содержимое файла с именем
student_records в каталоге, в котором он был запущен (в рабочем каталоге программы).
*Примечание: Имена файлов могут содержать любые символы, допустимые для данной файловой системы. Чтобы быть
переносимыми, я буду использовать только общепринятые символы ASCII.*

Reading from a file
To read from a file the file must first have been opened in one of the read modes:

**Чтение из файла**

Файл должен быть открыт в одном из режимов чтения перед любыми операциями записи


.. code-block:: d


    import std.stdio;
    import std.string;

    void main()
    {
        File file = File("student_records", "r");
        while (!file.eof())
        {
            string line = strip(file.readln());
            writeln("read line -> |", line);
        }
    }


Приведенная выше программа считывает все строки файла с именем student_records и
выводит эти строки на стандартный вывод.


Упражнения
----------

Напишите программу, которая берет имя файла у пользователя, открывает этот файл и записывает
все непустые строки этого файла в другой файл. Имя нового файла может
быть основано на имени исходного файла. Например, если исходным файлом является
foo.txt , новым файлом может быть foo.txt.out .
Решение приведено на странице (:ref:`решения для главы файлы<решения для главы файлы>`)

